import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/**
 * This class is responsible for wrapping groupings of 
 * <code>MarkovState</code>s into a <code>MarkovStateSet</code>
 */
public class MarkovStateSet implements Serializable
{
	private static final long serialVersionUID = -1747795771088910836L;
	private List<MarkovState> states;
	private int hashCode = 0;
	private boolean hashCodeNeedsUpdate = true;
	
	public MarkovStateSet()
	{
		states = new ArrayList<MarkovState>();
	}
	
	public MarkovStateSet(List<MarkovState> iStates)
	{
		states = iStates;
	}
	
	/**
	 * Clear the states in this MarkovStateSet
	 */
	public void clear()
	{
		hashCodeNeedsUpdate = true;
		states.clear();
	}
	
	/**
	 * Return the collection of states, in order of occurrence.
	 * 
	 * @return <code>List&lt;MarkovState&gt;</code>
	 */
	public List<MarkovState> getStates()
	{
		return states;
	}
	
	/**
	 * Pop a state set off the front of the prior states (FIFO/Queue)
	 * 
	 * @return <code>MarkovState</code> state that was popped off
	 */
	public MarkovState pop()
	{
		hashCodeNeedsUpdate = true;
		return states.remove(states.size()-1);
	}
	
	/**
	 * Push a state onto the back of the prior states (FIFO/Queue)
	 * 
	 * @param state <code>MarkovState</code>
	 */
	public void push(MarkovState state)
	{
		hashCodeNeedsUpdate = true;
		states.add(state);
	}
	
	/**
	 * Get the number of states in this <code>MarkovStateSet</code>
	 * 
	 * @return <code>int</code>
	 */
	public int size()
	{
		return states.size();
	}
	
	@Override
	public String toString()
	{
		String result = "MarkovStateSet@"+this.hashCode()+"=(";
		
		int numStates = states.size();
		for(int i=0; i < numStates; i++)
		{
			result += states.get(i);
			
			if(i < numStates-1)
				result += ",";
		}
		result += ")";
		
		return result;
	}
	
	@Override
	public int hashCode()
	{
		if(hashCodeNeedsUpdate)
		{
			String stateString = "";
			for(MarkovState ms : states)
			{
				stateString += ms.getToken();
			}
			hashCode = stateString.hashCode();
			
			hashCodeNeedsUpdate = false;
		}
		return hashCode;
	}
	
	@Override
	public boolean equals(Object arg0)
	{
		MarkovStateSet set2 = (MarkovStateSet)arg0;
		if(states.size() != set2.states.size())
			return false;
		
		for(int i=0; i < states.size(); i++)
			if(!states.get(i).equals(set2.states.get(i)))
				return false;
		
		return true;
	}
	//@Override
	/**
	 * Comparison function
	 * 
	 * @return <code>int</code>
	 */
	/*
	public int compareTo(MarkovStateSet testElement) 
	{
		if()
		// TODO Auto-generated method stub
		return 0;
	}*/
}
